package net.jcip.examples.pool.monitor;

import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

//5. 创建例子的主类通过创建一个类，名为 Main 并添加 main()方法。
// 参考 http://ifeve.com/testing-concurrent-applications-4/
public class Main {

    /**
     * 任务数量
     */
    private static final int TASK_COUNT = 1000;

    public static void main(String[] args) throws Exception {

//6. 使用Executors类的newCachedThreadPool()方法创建新的 Executor 对象。
//        ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newCachedThreadPool();//cached线程池比较贪婪,但是会回收线程
        ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(20);//用固定的20个线程处理，不会回收线程 多余的任务会排队

        long start = System.currentTimeMillis();
//7. 创建并提交10个 Task 对象给执行者。用随机数字初始化任务。
        for (int i = 0; i < TASK_COUNT; i++) {
            Task task = new Task(300);//假设每个线程任务执行300毫秒
            executor.submit(task);
        }

//8. 当激活任务不为0 显示线程信息
        while (executor.getActiveCount() != 0){
            showLog(executor);
            TimeUnit.SECONDS.sleep(1);
        }
        long end = System.currentTimeMillis();
        System.out.printf("执行 %d 任务,花了 %d 秒\n\n",TASK_COUNT,(end-start)/1000);
//9. 使用 shutdown() 方法关闭执行者。
        executor.shutdown();

//10. 另创建迭代为5的for循环。在每步，传递执行者调用 showLog() 方法写相关信息，并让线程休眠1秒。
        for (int i = 0; i < 5; i++) {
            showLog(executor);
            TimeUnit.SECONDS.sleep(1);
        }

//11. 使用 awaitTermination() 方法等待执行者的终结。
        executor.awaitTermination(1, TimeUnit.DAYS);

//12. 显示一条结束程序的信息。
        System.out.printf("Main: End of the program.\n");
    }

    //13. 实现 showLog() 方法，接收 Executor 作为参数。写关于pool的大小，任务的数量，和执行者状态的信息。

    /**
     在这个指南里，你实现了一个任务，它对它的执行线程进行了一段随机毫秒数的阻塞。然后，你发送10个任务给执行者，并且当你正在等待它们的终结的同时，你已经把关于执行者的状态的信息写入到操控台。你使用了以下的方法来获取 Executor 对象的状态：
     getCorePoolSize(): 此方法返回一个int数，表示线程的核心数。它是当执行者没有执行任何任务时，在内部线程池的线程数。
     getPoolSize(): 此方法返回一个int数，表示内部线程池的真实大小。
     getActiveCount(): 此方法返回一个int数，表示当前执行任务的线程数。
     getTaskCount(): 此方法返回一个long数，表示已经分配执行的任务数。
     getCompletedTaskCount(): 此方法返回一个long数，表示已经被这个执行者执行并结束执行的任务数。
     isShutdown(): 当 执行的 shutdown() 方法被调用来结束执行时，此方法返回 Boolean 值。
     isTerminating(): 当执行者正在操作shutdown()，但是还没结束时，此方法返回 Boolean 值。
     isTerminated(): 当这个执行者结束执行时，此方法返回 Boolean 值。
     * @param executor
     */
    private static void showLog(ThreadPoolExecutor executor) {
        System.out.printf("*********************");
        System.out.printf("Main: 线程池监控\n");
        System.out.printf("Main: Executor: Core Pool Size:%d\n", executor.getCorePoolSize());
        System.out.printf("Main: Executor: 一共多少人: %d\n", executor.getPoolSize());
        System.out.printf("Main: Executor: 繁忙多少人: %d\n", executor.getActiveCount());
        System.out.printf("Main: Executor: Task Count: %d\n", executor.getTaskCount());
        System.out.printf("Main: Executor: Completed Task Count:%d\n", executor.getCompletedTaskCount());
        System.out.printf("Main: Executor: Shutdown: %s\n", executor.isShutdown());
        System.out.printf("Main: Executor: Terminating:%s\n", executor.isTerminating());
        System.out.printf("Main: Executor: Terminated: %s\n", executor.isTerminated());
        System.out.printf("*********************\n");
    }
}

//1. 创建一个类，名为 Task，并实现 Runnable 接口.
class Task implements Runnable {

    //2. 声明一个私有 long 属性，名为 milliseconds.
    private long milliseconds;

    //3. 实现类的构造函数，初始化它的属性。
    public Task(long milliseconds) {
        this.milliseconds = milliseconds;
    }

    //4. 实现 run() 方法。通过 milliseconds 属性让线程进入一段时间休眠。
    @Override
    public void run() {
        System.out.printf("%s: Begin\n", Thread.currentThread().getName());
        try {
            TimeUnit.MILLISECONDS.sleep(milliseconds);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.printf("%s: End\n", Thread.currentThread().getName());
    }
}